/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_task_internal.h"
#include "downsampling/down_sampler.h"
#include "imageknife_internal.h"
#include "request/imageknife_request_internal.h"

namespace ImageKnifePro {

std::string ImageKnifeTaskInternal::GetTaskInfo(ImageRequestType type,
                                                std::shared_ptr<ImageKnifeRequestInternal> request)
{
    IMAGE_KNIFE_CHECK_RETURN(request == nullptr, "[Null Request] ");

    std::string source;
    switch (type) {
        case ImageRequestType::MAIN_SRC:
            source = "MainSrc";
            break;
        case ImageRequestType::PLACE_SRC:
            source = "PlaceSrc";
            break;
        case ImageRequestType::ERROR_SRC:
            source = "ErrorSrc";
            break;
        default:
            break;
    }

    if (request->IsPreload()) {
        return "[ID:" + request->GetNodeId() + " Animator:" + std::to_string(request->IsPreloadAnimator()) +
               " Type:" + source + "] ";
    }

    return "[ID:" + request->GetNodeId() + " VersionID:" + std::to_string(request->GetVersion()) +
           " Type:" + source + "] ";
}

std::string ImageKnifeTaskInternal::GetTaskInfo() const
{
    return GetTaskInfo(type_, request_);
}

std::string ImageKnifeTaskInternal::GetDisplayPixelmapInfo() const
{
    IMAGE_KNIFE_CHECK_RETURN(product.imageDataCache == nullptr, "Null Image DataCache");
    return "Pixelmap Ready: width:" +  std::to_string(product.imageDataCache->GetImageWidth()) +
           " height:" + std::to_string(product.imageDataCache->GetImageHeight()) +
           " size:" + std::to_string(product.imageDataCache->GetImageCacheSize()) +
           " format:" + std::to_string(static_cast<int>(product.imageDataCache->GetImageFormat()));
}

void ImageKnifeTaskInternal::SetIsAnimator()
{
    IMAGE_KNIFE_CHECK(request_ == nullptr);
    if (request_->IsPreload()) {
        isAnimator_ = request_->IsPreloadAnimator();
        return;
    }

    auto imageNode = ImageKnifeInternal::GetInstance().GetImageNode(request_->GetNodeId());
    if (imageNode == nullptr) {
        FatalError("Empty ImageNode When Set Animator Status");
        return;
    }

    isAnimator_ = imageNode->IsAnimator();
}

ImageFormat ImageKnifeTaskInternal::GetImageBufferFormat() const
{
    return imageBufferFormat_;
}

ImageSource *ImageKnifeTaskInternal::GetImageSource() const
{
    return imageSrc_;
}

ImageRequestType ImageKnifeTaskInternal::GetImageRequestType() const
{
    return type_;
}

std::shared_ptr<ImageKnifeRequest> ImageKnifeTaskInternal::GetImageKnifeRequest() const
{
    return request_;
}

void ImageKnifeTaskInternal::QueryImageBufferFormat()
{
    uint8_t *buffer;
    uint32_t length;

    if (product.imageBuffer != nullptr) {
        buffer = product.imageBuffer.get();
        length = product.imageLength;
    } else {
        EchoError("Empty Image Buffer (Query Image Format)");
        imageBufferFormat_ = ImageFormat::UNKNOWN;
        return;
    }

    imageBufferFormat_ = ImageKnifeInternal::GetInstance().fileTypeUtil.CheckImageFormat(buffer, length);

    Image_ErrorCode imgErrorCode = OH_ImageSourceNative_CreateFromData(buffer, length, &imageSource_);
    if (imgErrorCode != IMAGE_SUCCESS) {
        EchoError("Create ImageSource failed, error code: " + std::to_string(imgErrorCode));
        return;
    }

    // 创建定义图片信息的结构体对象，并获取图片信息
    OH_ImageSource_Info *imageInfo;
    OH_ImageSourceInfo_Create(&imageInfo);
    imgErrorCode = OH_ImageSourceNative_GetImageInfo(imageSource_, 0, imageInfo);
    if (imgErrorCode != IMAGE_SUCCESS) {
        EchoError("Failed to get imageInfo");
    }

    // 获取宽和高
    uint32_t width;
    uint32_t height;
    OH_ImageSourceInfo_GetWidth(imageInfo, &width);
    OH_ImageSourceInfo_GetHeight(imageInfo, &height);
    OH_ImageSourceInfo_Release(imageInfo);

    // 根据图片帧树判断图片格式，帧数大于1视为动图
    imgErrorCode = OH_ImageSourceNative_GetFrameCount(imageSource_, &frameCount_);
    if (imgErrorCode != IMAGE_SUCCESS || frameCount_ < 1) {
        EchoError("Get FrameCount Failed, error code: " + std::to_string(imgErrorCode));
    } else if (frameCount_ > 1) {
        isAnimationImage_ = true;
    }

    if (type_ == ImageRequestType::MAIN_SRC) {
        // 请求数据采集，记录主图信息
        request_->GetImageInfo().imageHeight = height;
        request_->GetImageInfo().imageWidth = width;
        request_->GetImageInfo().bufSize = length;
        request_->GetImageInfo().type = imageBufferFormat_;
        request_->GetImageInfo().frameCount = frameCount_;

        // 降采样，解码期望宽高计算
        auto option = request_->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK(option == nullptr);
        desiredImageSize_ = DownSampler::CalculateSize(imageBufferFormat_, {.width = width, .height = height},
                                                       request_->GetRequestImageSize(), option->downSampling);
        IMAGE_KNIFE_LOG(LOG_DEBUG, "%{public}s DownSampling Strategy:%{public}d Desired Size: %{public}d, %{public}d",
                        GetTaskInfo().c_str(), static_cast<int>(option->downSampling),
                        desiredImageSize_.width, desiredImageSize_.height);
    }
}

std::shared_ptr<ImageKnifeRequestInternal> ImageKnifeTaskInternal::GetImageKnifeRequestInternal() const
{
    return request_;
}

OH_ImageSourceNative *ImageKnifeTaskInternal::GetImageSourceNative() const
{
    return imageSource_;
}

uint32_t ImageKnifeTaskInternal::GetImageSourceFrameCount() const
{
    return frameCount_;
}

Image_Size ImageKnifeTaskInternal::GetDesiredImageSize() const
{
    return desiredImageSize_;
}
} // end of namespace
